////////////////////////////////////////////////////////////////////////////////
// This file is part of the Mist compiler.                                    //
//                                                                            //
// Copyright (C) 2009 The Mist project                                        //
//                                                                            //
// For a list of contributors, see the COMMITTERS file.                       //
//                                                                            //
// The Mist compiler is free software: you can redistribute it and/or modify  //
// it under the terms of the GNU General Public License as published by       //
// the Free Software Foundation, either version 3 of the License, or          //
// (at your option) any later version.                                        //
//                                                                            //
// The Mist compiler is distributed in the hope that it will be useful,       //
// but WITHOUT ANY WARRANTY; without even the implied warranty of             //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              //
// GNU General Public License for more details.                               //
//                                                                            //
// You should have received a copy of the GNU General Public License          //
// in the COPYING file. If not, see <http://www.gnu.org/licenses/>.           //
////////////////////////////////////////////////////////////////////////////////

///
/// \file
/// Contains the implementation of the echo wrapper.
///

#include "finderror1.hpp"

////////////////////////////////////////////////////////////////////////////////
// Includes                                                                   //
////////////////////////////////////////////////////////////////////////////////

#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH

#include <boost/algorithm/string/replace.hpp>
using boost::replace_all;

#include "common/assert.hpp"
#include "common/ptr.hpp"
#include "nodes.hpp"
#include "operator.hpp"
#include "tree.hpp"
#include "messages.hpp"
#include "navigator.hpp"

////////////////////////////////////////////////////////////////////////////////
// FindError1Visitor Class                                                    //
////////////////////////////////////////////////////////////////////////////////

/// Visits the nodes of an abstract syntax tree to find and report the
/// errors that were not caught by the parser, but do not need a symbol-table
/// to be found.
///
class FindError1Visitor : public Navigator {
	public:
		
		/// Construct a find-error-1 visitor.
		///
		FindError1Visitor(wptr<Messages> messages);
		
		VISIT_FUNCTIONS_FROM (
			(WhileStatement)
			(ForStatement)
			(FunctionDeclaration)
		)
	
	private:
		
		wptr<Messages> _messages;
};

////////////////////////////////////////////////////////////////////////////////
// Function Implementations                                                   //
////////////////////////////////////////////////////////////////////////////////

void find_error_1(wptr<Node> tree, wptr<Messages> messages) {
	assert(tree);
	assert(messages);
	
	sptr<FindError1Visitor> visitor(new FindError1Visitor(messages));
	
	tree->accept(visitor);
}

////////////////////////////////////////////////////////////////////////////////

FindError1Visitor::FindError1Visitor(wptr<Messages> messages) : _messages(messages) {
} // intentionally empty

void FindError1Visitor::visit(wptr<WhileStatement> node) {
	assert(node);
	
	// If this while loop has no body
	//
	if (node->statement.size() == 0)
		_messages->add("missing at location", *node->location, "while loop body");
	
	// If this while loop has more than one body
	//
	if (node->statement.size() > 1) {
		foreach (wptr<Node> stmt, node->statement)
			_messages->add("too many", *stmt->location, "bodies:" + string(*node->location), "while loop bodies", "only one");
	}
	
	Navigator::visit(node);
}

void FindError1Visitor::visit(wptr<ForStatement> node) {
	assert(node);
	
	// If this for loop has no body
	//
	if (node->statement.size() == 0)
		_messages->add("missing at location", *node->location, "for loop body");
	
	// If this for loop has more than one body
	//
	if (node->statement.size() > 1) {
		foreach (wptr<Node> stmt, node->statement)
			_messages->add("too many", *stmt->location, "bodies:" + string(*node->location), "for loop bodies", "only one");
	}
	
	Navigator::visit(node);
}

void FindError1Visitor::visit(wptr<FunctionDeclaration> node) {
	assert(node);
	
	// If a logical variable is initialized
	//
	foreach (wptr<VariableDeclaration> lv, node->logicalVars) {
		foreach (VariableDeclaration::Pair p, lv->pairs)
			if (p.init)
				_messages->add("logical var init", *p.init->location, p.name->text);
	}
	
	// If the function ensurance contains a body
	//
	if (node->ensurance) {
		foreach (wptr<CompoundStatement> body, node->body)
			_messages->add("ensurance body", *body->location, "bodies:" + string(*node->location), node->name->text);
	}
	
	// If the function declaration contains no body
	//
	if (!node->ensurance && node->body.size() == 0)
		_messages->add("missing at location", *node->location, "function body");
	
	// If the function declaration contains more than one body
	//
	if (!node->ensurance && node->body.size() > 1) {
		foreach (wptr<CompoundStatement> body, node->body)
			_messages->add("too many", *body->location, "bodies:" + string(*node->location), "function bodies", "only one");
	}
	
	Navigator::visit(node);
}
